#include "StdAfx.h"
#include "IWeapon.h"
#include "StateFactory.h"
#include "../kernel.h"

extern Kernel* g_kernel;

#define TIME g_kernel->GetTime()

IWeapon::IWeapon(void) : IEntity()
{
    //IEntity::IEntity();

    m_FSM.SetOwner( this );
    m_weaponTime = 0.0f;
    m_reloadTime = 0.0f;
    m_owner      = NULL;
    m_flags      |= EF_WP_ONGROUND;
    m_hitBounds.Reset();

    AddState( "WP_FIRING" , StateFactory::GetInstance()->CreateState( "WP_FIRING" ) );
    AddState( "WP_READY" , StateFactory::GetInstance()->CreateState( "WP_READY" ) );
    AddState( "WP_RELOADING" , StateFactory::GetInstance()->CreateState( "WP_RELOADING" ) );
    AddState( "IDLE", StateFactory::GetInstance()->CreateState( "IDLE" ) );

    SetState( "IDLE" );
}

IWeapon::~IWeapon(void)
{

}

///** Apply Common Dictionary Attributes */
//void IWeapon::Apply()
//{
//
//}

/** Update */
void IWeapon::Update(long deltaTime)
{
    m_FSM.Update();
    CheckAutoReload();
    if ( !(m_flags & EF_WP_ONGROUND)  )
    {
        if ( m_flags & EF_WP_DRAWN )
        {
            CheckAutoReload();
        } 
        else
        {
            // don't draw
            m_flags |= EF_NOTONSCREEN;
        }
    }
}

/** Fire this weapon */
void IWeapon::Fire()
{
    if ( IsReady() )
    {
        SetState( "WP_FIRING" );
        m_owner->SetState( "ATTACKING1" );
        m_weaponTime = TIME + m_attributes.GetFloat("weapontime");
    }
    else
    {
        SetState( "WP_RELOADING" );
    }
}

/** Reload this weapon */
void IWeapon::Reload()
{
    SetState( "WP_RELOADING" );
    m_reloadTime = TIME + m_attributes.GetFloat("reloadtime");

    if ( m_attributes.Has("reload") )
    {
        // first check amount in ammo Bin
        int amountLeft = m_attributes.GetInt("ammobin");

        // can't reload
        if ( amountLeft <= 0 ) {
            m_reloadTime = 0;         
            return;
        }

        // how many bullets can we reload
        int ammoToAdd = m_attributes.GetInt("reload");
        // fetch amount in clip
        int ammoInClip = m_attributes.GetInt("clip");

        // max allowed in the clip
        int clipMax = m_attributes.GetInt("clipmax");
        // calculate how many bullets we can add
        int ableToAdd = clipMax - ammoInClip;
        if ( ableToAdd < ammoToAdd )
            ammoToAdd = ableToAdd;
        
        amountLeft = amountLeft - ammoToAdd;
        if ( amountLeft < 0 )
        {   // we can't add what we don't have
            ammoToAdd += amountLeft;
            // reset the amount left.
            amountLeft = 0;
        }

        // store how many bullets we have
        ammoToAdd += m_attributes.GetInt("clip");
        // add the new ammo to our clip
        m_attributes.SetInt( "clip", ammoToAdd );
        m_attributes.SetInt( "ammobin", amountLeft );
    }
}

/** Check for reload */
void IWeapon::CheckAutoReload()
{
    if ( m_attributes.Has("reload") )
    {
        // an empty clip
        if ( m_attributes.GetInt( "clip" ) <= 0 )
            Reload();
    }
}

/** Weapon is Ready */
bool IWeapon::IsReady()
 {
    if ( TIME > m_reloadTime && TIME > m_weaponTime )
    {
        SetState( "WP_READY" );
    }
    return (GetState() == "WP_READY");
}


/** Weapon is Firing */
bool IWeapon::IsFiring()
{
    return (GetState() == "WP_FIRING");
}

/** Weapon is reloading */
bool IWeapon::IsReloading()
{
    return (GetState() == "WP_RELOADING");
}

/** Item is Idle, on the ground */
bool IWeapon::CanPickUp()
{
    return (GetState() == "IDLE");
}

/** Collide with this weapon */
bool IWeapon::CollideWith( IEntity* ent )
{
    // this weapon has not been equiped
    if ( CanPickUp() ) {
        ent->PickUpItem( this );
        IsReady();
    } else {// unleash this weapons furry.
        ent->Damage( -m_attributes.GetInt( "damage" ) );
    }
    return false;
}